#include "tabview.h"
using namespace std;

// event table for the tab viewer
BEGIN_EVENT_TABLE(tabView, wxWindow)
  EVT_ERASE_BACKGROUND  (tabView::OnEraseBackground)
  EVT_PAINT             (tabView::OnPaint)
END_EVENT_TABLE()

tabView::tabView(wxWindow *parent, song *theSongInit, engine *theEngineInit)
               : wxWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(600, 200), wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER) {
  theSong = theSongInit;
  theEngine = theEngineInit;
  SetBackgroundColour(*wxWHITE);
  offset = 0;
  imageGKey.LoadFile(_("./images/gkey.png"));
  imageNote16Up.LoadFile(_("./images/note_16_up.png"));
  imageNote16Down.LoadFile(_("./images/note_16_down.png"));
  imageNote8Up.LoadFile(_("./images/note_8_up.png"));
  imageNote8Down.LoadFile(_("./images/note_8_down.png"));
  imageNote4Up.LoadFile(_("./images/note_4_up.png"));
  imageNote4Down = imageNote4Up.Rotate90(true);
  imageNote4Down = imageNote4Down.Rotate90(true);
  imageNote2Up.LoadFile(_("./images/note_2_up.png"));
  imageNote2Down = imageNote2Up.Rotate90(true);
  imageNote2Down = imageNote2Down.Rotate90(true);
  imageNote1Up.LoadFile(_("./images/note_1_up.png"));
  imageNote1Down = imageNote1Up.Rotate90(true);
  imageNote1Down = imageNote1Down.Rotate90(true);
  imageRest4.LoadFile(_("./images/rest_4.png"));
  imageRest8.LoadFile(_("./images/rest_8.png"));
  imageRest16.LoadFile(_("./images/rest_16.png"));
}

tabView::~tabView() {

}

void tabView::doUpdate() {

  OnPaint(*((new wxPaintEvent)));
  Refresh();
}

void tabView::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
{
    // do nothing. I just don't want the background to be erased, you know.
}

// paint the current virtual world
void tabView::OnPaint(wxPaintEvent& event) {
  int i, countCounter, barCounter = 0;
  int prevCounter;
  bool firstNote = true;
  wxPaintDC dc(this);
  wxRect surface = GetUpdateRegion().GetBox();
  wxCoord x, y;
  x = surface.GetX();
  y = surface.GetY();
  width = surface.GetWidth();
  height = surface.GetHeight();
  // white background
  dc.SetPen(*wxWHITE_PEN);
  dc.SetBrush(*wxWHITE_BRUSH);
  dc.DrawRectangle(x, y, width, height);
  // some parameters
  int positionVertical = 30;
  int widthPerCount = 16;
  int positionHorizontal = 7 - (int)(ceil(offset)) * widthPerCount * theSong->metertop;
  int startPositionHorizontal = positionHorizontal;
  int sizeBarVertical = 8;
  int noteCountGood = 0, noteCountWrong = 0;
  // extra vars
  float countCurrentNote;
  // draw the horizontal lines
  dc.SetPen(*wxLIGHT_GREY_PEN);
  for(i = 0; i < 5; i++) {
    dc.DrawLine(x, y + positionVertical + i * sizeBarVertical, x + width, y + positionVertical + i * sizeBarVertical);

  }
  // draw the horizontal lines for guitar tabs
  for(i = 0; i < 6; i++) {
    dc.DrawLine(x, y + positionVertical + 4 * sizeBarVertical + 50 + i* sizeBarVertical, x + width, y + positionVertical + 4 * sizeBarVertical + 50 + i* sizeBarVertical);
  }
  // G-key
  dc.DrawBitmap(imageGKey, positionHorizontal, positionVertical - 10);
  positionHorizontal += 30;
  // meter
  dc.DrawText(wxString::Format(_("%d"), theSong->metertop), positionHorizontal, positionVertical + sizeBarVertical * 0);
  dc.DrawText(wxString::Format(_("%d"), theSong->meterbottom), positionHorizontal, positionVertical + sizeBarVertical * 2);
  positionHorizontal += 20;
  // draw the notes and extra info
  wxImage *tmpImage;
  countCounter = 0;
  dc.SetFont(wxFont(8, wxSWISS, wxNORMAL, wxNORMAL));
  for(i = 0; i < (int)theSong->notes.size(); i++) {
    if(theSong->notes[i]->status == 2)
      noteCountGood++;
    if(theSong->notes[i]->status == 1)
      noteCountWrong++;
    // increase counter
    prevCounter = countCounter;
    countCounter += 16 / theSong->notes[i]->type;
    // determine how many counts this note is
    countCurrentNote = theSong->metertop / ((float)theSong->notes[i]->type / theSong->meterbottom);
    // draw the image of the note
    if(theSong->notes[i]->rest) {
      // a rest
      if(theSong->notes[i]->type == 1 || theSong->notes[i]->type == 2) {
        // draw a box
        dc.SetPen(*wxBLACK_PEN);
        dc.SetBrush(*wxBLACK_BRUSH);
        if(theSong->notes[i]->type == 1) {
          // full rest
          dc.DrawRectangle(positionHorizontal, positionVertical + sizeBarVertical + 1, 10, (sizeBarVertical - 2) / 2);
        } else if(theSong->notes[i]->type == 2) {
          // half rest
          dc.DrawRectangle(positionHorizontal, positionVertical + (int)(sizeBarVertical * 1.5) + 1, 10, (sizeBarVertical - 2) / 2);
        }
      } else {
        if(theSong->notes[i]->type == 4) {
          // quarter rest
          tmpImage = &imageRest4;
        } else if(theSong->notes[i]->type == 8) {
          // eigth rest
          tmpImage = &imageRest8;
        } else if(theSong->notes[i]->type == 16) {
          // sixteenth rest
          tmpImage = &imageRest16;
        } else {
          tmpImage = &imageRest16;
        }
        // draw the rest
        dc.DrawBitmap(*tmpImage, positionHorizontal,
                        positionVertical + 6);
      }
    } else {
      // normal note, check the length
      if(theSong->notes[i]->type == 1) {
        // full note (semi-breve)
        if(theSong->notes[i]->upsideDown)
          tmpImage = &imageNote1Down;
        else
          tmpImage = &imageNote1Up;
      } else if(theSong->notes[i]->type == 2) {
        // half note (minim)
        if(theSong->notes[i]->upsideDown)
          tmpImage = &imageNote2Down;
        else
          tmpImage = &imageNote2Up;
      } else if(theSong->notes[i]->type == 4) {
        // quarter note (crochet)
        if(theSong->notes[i]->upsideDown)
          tmpImage = &imageNote4Down;
        else
          tmpImage = &imageNote4Up;
      } else if(theSong->notes[i]->type == 8) {
        // eighth note (quaver)
        if(theSong->notes[i]->upsideDown)
          tmpImage = &imageNote8Down;
        else
          tmpImage = &imageNote8Up;
      } else if(theSong->notes[i]->type == 16) {
        // sixteenth note (semi-quaver)
        if(theSong->notes[i]->upsideDown)
          tmpImage = &imageNote16Down;
        else
          tmpImage = &imageNote16Up;
      } else {
        tmpImage = &imageNote8Down;
      }
      // draw it
      if(theSong->notes[i]->upsideDown)
        dc.DrawBitmap(*tmpImage, positionHorizontal,
                      positionVertical + 21 + sizeBarVertical*3 +
                      ((int)(sizeBarVertical * 3.5) * (4 - theSong->notes[i]->octave - (theSong->notes[i]->pitch < 2 ? 1 : 0))) - theSong->notes[i]->pitch * (sizeBarVertical / 2));
      else
        dc.DrawBitmap(*tmpImage, positionHorizontal,
                      positionVertical + 21 +
                      ((int)(sizeBarVertical * 3.5) * (4 - theSong->notes[i]->octave - (theSong->notes[i]->pitch < 2 ? 1 : 0))) - theSong->notes[i]->pitch * (sizeBarVertical / 2));
      // sharp or flat sign at the note
      if(theSong->notes[i]->sharp) {
        dc.DrawText(_("#"), positionHorizontal - 3,
                      positionVertical + 17 + sizeBarVertical*3 +
                      ((int)(sizeBarVertical * 3.5) * (4 - theSong->notes[i]->octave - (theSong->notes[i]->pitch < 2 ? 1 : 0))) - theSong->notes[i]->pitch * (sizeBarVertical / 2));
      }
      if(theSong->notes[i]->flat) {
        dc.DrawText(_("b"), positionHorizontal - 3,
                      positionVertical + 17 + sizeBarVertical*3 +
                      ((int)(sizeBarVertical * 3.5) * (4 - theSong->notes[i]->octave - (theSong->notes[i]->pitch < 2 ? 1 : 0))) - theSong->notes[i]->pitch * (sizeBarVertical / 2));
      }
      // draw the textual pitch underneath
      wxString drawPitch = theSong->notes[i]->pitchString;
      if(theSong->notes[i]->sharp) {
        drawPitch.Append(_("#"));
      }
      if(theSong->notes[i]->flat) {
        drawPitch.Append(_("b"));
      }
      switch(theSong->notes[i]->status) {
        case 1:
          dc.SetTextForeground(*wxRED);
          break;
        case 2:
          dc.SetTextForeground(wxColor(_("LIME GREEN")));
          break;
        default:
          dc.SetTextForeground(*wxBLACK);
      }
      dc.DrawText(drawPitch, positionHorizontal, positionVertical + sizeBarVertical * 4 + 20);
      dc.SetTextForeground(*wxBLACK);
    }
    // draw the textual pitch underneath
    if(theSong->notes[i]->rest) {
      dc.SetPen(*wxBLACK_PEN);
      dc.DrawText(_("-"), positionHorizontal, positionVertical + sizeBarVertical * 4 + 20);
    }
    // draw horizontal line for the length of the note
    /*dc.SetPen(*wxBLACK_PEN);
    dc.DrawLine(positionHorizontal,
                positionVertical + 20 * sizeBarVertical + ((int)(sizeBarVertical * 3.5) * (4 - theSong->notes[i]->octave)) - theSong->notes[i]->pitch * (sizeBarVertical / 2),
                positionHorizontal + (int)(countCurrentNote * widthPerCount),
                positionVertical + 20 * sizeBarVertical + ((int)(sizeBarVertical * 3.5) * (4 - theSong->notes[i]->octave)) - theSong->notes[i]->pitch * (sizeBarVertical / 2));
                */
    // draw tabs for guitar
    if(theSong->notes[i]->string > 0 && theSong->notes[i]->fret > 0) {
      dc.DrawText(wxString::Format(_("%i"), theSong->notes[i]->fret), positionHorizontal,
                  positionVertical + sizeBarVertical * 4 + 43 + (6 - theSong->notes[i]->string) * sizeBarVertical);
    }
    // check for finished bar
    if(firstNote || prevCounter % (16 / theSong->metertop * theSong->meterbottom) == 0) {
      firstNote = false;
      barCounter++;
      // bar is finished, draw vertical line
      dc.SetPen(*wxLIGHT_GREY_PEN);
      dc.DrawLine(positionHorizontal, positionVertical, positionHorizontal, positionVertical + sizeBarVertical * 4 + 1);
      // vertical line for guitar tabs
      dc.DrawLine(positionHorizontal, positionVertical + 4 * sizeBarVertical + 50, positionHorizontal, positionVertical + 4 * sizeBarVertical + 50 + sizeBarVertical * 5 + 1);

      positionHorizontal += 1;
    }
    // determine how much further to go
    positionHorizontal += (int)(countCurrentNote * widthPerCount);
  }
  // draw the metronome
  for(i = 0; i < barCounter * theSong->metertop + 1; i++) {
    if(i != theEngine->countNr) {
      dc.SetPen(*wxGREY_PEN);
      dc.SetBrush(*wxGREY_BRUSH);
    } else {
      dc.SetPen(*wxRED_PEN);
      dc.SetBrush(*wxRED_BRUSH);
    }
    dc.DrawCircle(startPositionHorizontal + 50 + i * widthPerCount * theSong->metertop + 3 + widthPerCount / 2, positionVertical + sizeBarVertical * 4 + 50 + sizeBarVertical * 5 + 20, 7);
  }

  // update the score gauge
  if(theSong->notes.size()) {
    if(noteCountWrong || noteCountGood)
      theGauge->SetValue((int)(((float)noteCountGood / (noteCountWrong + noteCountGood)) * 100));
    else
      theGauge->SetValue(100);
  } else {
    theGauge->SetValue(0);
  }
}

void tabView::handleScollBar() {
  offset = ((float)theScrollBar->GetThumbPosition() / theScrollBar->GetRange()) * theSong->totalLength;
  doUpdate();
}

void tabView::resizeScrollBar() {
  // position
  int scrlPosition =  (int)(((float)theScrollBar->GetThumbPosition() / theScrollBar->GetRange()) * theSong->totalLength);
  // width of the thumb
  int scrlThumbSize = (width / (16 * theSong->metertop));
  // range
  int scrlRange = (int)ceil(theSong->totalLength);
  theLog->AppendText(wxString::Format(_("Resize: %d %d %d %d\n"), scrlPosition, scrlThumbSize, scrlRange, width));
  // set the scrollbar
  theScrollBar->SetScrollbar(scrlPosition, scrlThumbSize, scrlRange, scrlThumbSize);
}
